<template>
  <div class="fx-form">
    <slot></slot>
  </div>
</template>

<script lang="ts">
import { computed, defineComponent, onBeforeMount, onBeforeUnmount, PropType, provide, reactive, Ref } from 'vue'
import { LabelPosition, labelPositionArr, RulesProps } from '@/base/form/formTypes'
import { FormValidatorFun } from '@/base/form/formItem.vue'
import mitt, { Emitter } from 'mitt'

export type formItemRules = RulesProps[] | RulesProps | undefined
type ValidatorMitt = { prop: string, fun: FormValidatorFun }

interface FormProps {
  rules: { [propName: string]: formItemRules },
  labelWidth: string | number,
  labelPosition: LabelPosition,
}

export default defineComponent({
  name: 'FForm',
  props: {
    // 验证规则
    rules: {
      type: Object as PropType<{ [propName: string]: formItemRules }>,
      default: () => {
        return {}
      }
    },
    // 表头宽度
    labelWidth: {
      type: [String, Number] as PropType<string | number>,
      default: 100
    },
    // 表头位置
    labelPosition: {
      type: String as PropType<LabelPosition>,
      default: 'left',
      validator (val: string): boolean {
        return labelPositionArr.includes(val)
      }
    }
  },
  setup (props: FormProps) {
    // form到formItem传递监听
    const formMitt: Emitter = mitt()
    // 监听formData下所有需要监听验证的信息
    const formValidatorFunArr = reactive<ValidatorMitt[]>([])
    // 传递label位置
    provide<Ref<LabelPosition>>('labelPosition', computed(() => props.labelPosition))
    // 传递label宽度
    provide<Ref<string | number>>('labelWidth', computed(() => props.labelWidth))
    // 传递rules
    provide<Ref<{ [propName: string]: formItemRules }>>('formRules', computed(() => props.rules))
    // 传递监听器
    provide<Emitter['emit']>('formMittEmit', formMitt.emit)
    // 合并所有验证方法
    const handleAddValidator = (val: ValidatorMitt | undefined) => {
      if (val) formValidatorFunArr.push(val)
    }
    // formData组件验证方法
    const validator = async (cb: (val: boolean) => void): Promise<void> => {
      let isValidator = true
      for (let i = 0; i < formValidatorFunArr.length; i++) {
        const item = await formValidatorFunArr[i].fun()
        if (!item) isValidator = false
      }
      cb(isValidator)
    }
    // formData单个验证方法
    const validatorField = async (val: string, cb: (val: boolean) => void): Promise<void> => {
      let isValidator = true
      const valida = formValidatorFunArr.find((item: ValidatorMitt) => item.prop === val)
      if (valida) {
        const item = await valida.fun()
        if (!item) isValidator = false
      }
      cb(isValidator)
    }

    onBeforeMount(() => {
      // 监听获取formData下的所有验证方法
      formMitt.on<ValidatorMitt | undefined>('formValidator', handleAddValidator)
    })

    onBeforeUnmount(() => {
      formMitt.off('formValidator', handleAddValidator)
    })

    return {
      validator,
      validatorField
    }
  }
})
</script>
